package com.ssy.lingxi.order.serviceimpl.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.order.OrderTypeEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.dataauth.handler.RedisServiceHolder;
import com.ssy.lingxi.dataauth.model.constant.DataAuthConstant;
import com.ssy.lingxi.dataauth.model.dto.DataAuthDto;
import com.ssy.lingxi.member.merchant.api.feign.inner.MemberAbilitySalesFeign;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberSalesCountFeignVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberSalesFindUserIdVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.*;
import com.ssy.lingxi.order.entity.OrderDO;
import com.ssy.lingxi.order.entity.QOrderDO;
import com.ssy.lingxi.order.entity.QOrderProductDO;
import com.ssy.lingxi.order.model.constant.OrderOuterStatusEnum;
import com.ssy.lingxi.order.model.vo.basic.request.*;
import com.ssy.lingxi.order.model.vo.basic.response.*;
import com.ssy.lingxi.order.repository.OrderRepository;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.web.IMemberSalesAchievementCountService;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务员业绩统计的相关接口
 *
 * 由于使用querydsl分组以后再查询总条数会报错
 * 所以关于分页的总条数都是第二次不带分页数据的查询得到的
 *
 * @author 郑小翠
 * @version 2.02.18
 * @date 2022-03-14
 */
@Service
public class MemberSalesAchievementCountServiceImpl implements IMemberSalesAchievementCountService {

    @Resource
    MemberAbilitySalesFeign memberAbilitySalesFeign;

    @Resource
    OrderRepository orderRepository;

    @Resource
    IBaseCacheService baseCacheService;

    @Resource
    private JPAQueryFactory jpaQueryFactory;


    /**
     * 业务员业绩统计查询
     *
     * @param headers 登录信息
     * @param pageVO  业务员业绩统计查询条件
     * @return 返回业务员业绩统计信息
     */
    @Override
    public Wrapper<PageData<MemberSalesAchievementCountVO>> findAllMemberSalesAchievement(HttpHeaders headers, @Valid OrderMemberSalesCountVO pageVO) {
        baseCacheService.needLoginFromBusinessPlatform(headers);
        String token = headers.getFirst("token");
        String referer = headers.getFirst("Referer");
        return achievementCount(token, referer, pageVO);

    }

    /**
     * 根据业务员用户id返回下级会员
     *
     * @param pageVO 搜索条件
     * @return 返回会员信息
     */
    @Override
    public Wrapper<PageData<MemberSalesMemberQueryVO>> findByUserId(HttpHeaders headers, @Valid MemberSalesMemberCountVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        return memberCount(loginUser.getMemberId(), loginUser.getMemberRoleId(), pageVO);
    }

    /**
     * 业务员业绩商品统计详情
     *
     * @param headers 登录信息
     * @param pageVO  查询条件
     * @return 返回购买的商品信息
     */
    @Override
    public Wrapper<PageData<MemberSalesCountCommodityQueryVO>> commodityInformation(HttpHeaders headers, @Valid MemberSalesCountCommodityVO pageVO) {
        baseCacheService.needLoginFromBusinessPlatform(headers);
        PageData<MemberSalesCountCommodityQueryVO> pageDataWrapper = commodityInformation(pageVO);
        pageVO.setCurrent(0);
        pageVO.setPageSize(0);
        PageData<MemberSalesCountCommodityQueryVO> total = commodityInformation(pageVO);
        return Wrapper.success(new PageData<>(total.getTotalCount(), pageDataWrapper.getData()));
    }

    /**
     * 业务员订单明细
     *
     * @param headers 登录信息
     * @param pageVO  搜索条件
     * @return 返回以商品SkuId为维度的订单明细
     */
    @Override
    public Wrapper<PageData<MemberSalesCountOrderDetailsQueryVO>> orderDetails(HttpHeaders headers, @Valid MemberSalesCountOrderDetailsVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        Integer source = loginUser.getLoginSource();
        String token = headers.getFirst("token");
        String referer = headers.getFirst("Referer");
        Long headerUserId = loginUser.getUserId();
        return orderCount(source,referer,token,loginUser.getMemberId(), loginUser.getMemberRoleId(),headerUserId, pageVO);
    }

    /**
     * 导出业务员业绩统计
     *
     * @param token  token
     * @param pageVO 搜索条件
     */
    @Override
    public void exportFindAllMemberSales(HttpServletResponse response, @Valid MemberSalesCountExportVO pageVO, String token, String referer) {
        baseCacheService.needLoginFromBusinessPlatform(token);
        List<MemberSalesAchievementCountVO> memberSalesAchievementList = new ArrayList<>();
        // 构造统计业务员信息VO
        OrderMemberSalesCountVO memberSalesCountVO = new OrderMemberSalesCountVO();
        memberSalesCountVO.setStartTime(pageVO.getStartTime());
        memberSalesCountVO.setCurrent(1);
        memberSalesCountVO.setPageSize(5000);
        memberSalesCountVO.setTitle(pageVO.getTitle());
        memberSalesCountVO.setName(pageVO.getName());
        Wrapper<PageData<MemberSalesAchievementCountVO>> memberSalesAchievementCountVO = achievementCount(token, referer, memberSalesCountVO);
        if (ObjectUtil.isNotNull(memberSalesAchievementCountVO.getData())) {
            memberSalesAchievementList.addAll(memberSalesAchievementCountVO.getData().getData());
        }
        // 业务员数据不为空时
        List<Map<String, Object>> rows = memberSalesAchievementList.stream().map(memberSales -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("所属机构", memberSales.getTitle());
            map.put("业务员姓名", memberSales.getName());
            map.put("下级会员数", memberSales.getMemberCount());
            map.put("下单次数", memberSales.getOrderCount());
            map.put("订单应付金额", ObjectUtils.isEmpty(memberSales.getAmountPayable()) ? BigDecimal.ZERO : memberSales.getAmountPayable());
            map.put("订单已付金额", ObjectUtils.isEmpty(memberSales.getAmountPaid()) ? BigDecimal.ZERO : memberSales.getAmountPaid());
            map.put("售后退款金额", ObjectUtils.isEmpty(memberSales.getRefundAmount()) ? BigDecimal.ZERO : memberSales.getRefundAmount());
            return map;
        }).collect(Collectors.toList());

        ExcelWriter writer = ExcelUtil.getBigWriter();
        CellStyle style = writer.getHeadCellStyle();
        style.setWrapText(true);
        writer.write(rows);
        String fileName = "业务员业绩统计-" + DateUtil.date() + ".xls";
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }

    }

    /**
     * 导出会员统计信息
     *
     * @param response 网络信息
     * @param token    token
     * @param pageVO   搜索条件
     */
    @Override
    public void exportFindByUserId(HttpServletResponse response, @Valid MemberSalesMemberCountExportVO pageVO, String token) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(token);
        List<MemberSalesMemberQueryVO> queryList = new ArrayList<>();
        MemberSalesMemberCountVO requestVO = new MemberSalesMemberCountVO();
        requestVO.setMemberName(pageVO.getMemberName());
        requestVO.setUserId(pageVO.getUserId());
        requestVO.setCountTime(pageVO.getCountTime());
        requestVO.setCurrent(0);
        requestVO.setPageSize(0);
        Wrapper<PageData<MemberSalesMemberQueryVO>> memberSalesMemberQueryVO = memberCount(loginUser.getMemberId(), loginUser.getMemberRoleId(), requestVO);
        if (ObjectUtil.isNotNull(memberSalesMemberQueryVO.getData())) {
            queryList.addAll(memberSalesMemberQueryVO.getData().getData());
        }
        // 业务员数据不为空时
        List<Map<String, Object>> rows = queryList.stream().map(memberSales -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("会员ID", memberSales.getMemberId());
            map.put("下级会员名称", memberSales.getMemberName());
            map.put("会员角色", memberSales.getRoleName());
            map.put("订单量",ObjectUtils.isEmpty(memberSales.getOrderCount()) ? 0 : memberSales.getOrderCount() );
            map.put("订单应付金额",ObjectUtils.isEmpty(memberSales.getAmountPayable()) ? BigDecimal.ZERO : memberSales.getAmountPayable());
            map.put("订单已付金额", ObjectUtils.isEmpty(memberSales.getAmountPaid()) ? BigDecimal.ZERO : memberSales.getAmountPaid());
            map.put("售后退款金额", ObjectUtils.isEmpty(memberSales.getRefundAmount()) ? BigDecimal.ZERO : memberSales.getRefundAmount());
            return map;
        }).collect(Collectors.toList());

        ExcelWriter writer = ExcelUtil.getBigWriter();
        CellStyle style = writer.getHeadCellStyle();
        style.setWrapText(true);
        writer.write(rows);

        String fileName = "下级会员统计信息-" + DateUtil.date() + ".xls";
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }

    }

    /**
     * 导出商品统计
     *
     * @param response 网络信息
     * @param token    token
     * @param pageVO   搜索条件
     */
    @Override
    public void exportCommodityInformation(HttpServletResponse response, @Valid MemberSalesCountCommodityVO pageVO, String token) {
        baseCacheService.needLoginFromBusinessPlatform(token);
        List<MemberSalesCountCommodityQueryVO> queryList = new ArrayList<>();
        pageVO.setCurrent(0);
        pageVO.setPageSize(0);
        PageData<MemberSalesCountCommodityQueryVO> memberSalesCountCommodityQueryVO = commodityInformation(pageVO);
        if (!CollectionUtils.isEmpty(memberSalesCountCommodityQueryVO.getData())) {
            queryList.addAll(memberSalesCountCommodityQueryVO.getData());
        }
        // 商品数据不为空时
        List<Map<String, Object>> rows = queryList.stream().map(commodity -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("商品skuID", commodity.getSkuId());
            if (StringUtils.hasLength(commodity.getSpec())) {
                map.put("商品名称规格属性", commodity.getCommodityName().concat("-").concat(commodity.getSpec()));
            } else {
                map.put("商品名称规格属性", commodity.getCommodityName());
            }
            map.put("品类", commodity.getCategory());
            map.put("数量", commodity.getQuantity());
            map.put("销售额", commodity.getAmount());
            map.put("已收款金额", ObjectUtils.isEmpty(commodity.getPaidAmount()) ? BigDecimal.ZERO : commodity.getPaidAmount());
            map.put("售后退款金额", ObjectUtils.isEmpty(commodity.getRefundAmount()) ? BigDecimal.ZERO : commodity.getRefundAmount());
            return map;
        }).collect(Collectors.toList());

        ExcelWriter writer = ExcelUtil.getBigWriter();
        CellStyle style = writer.getHeadCellStyle();
        style.setWrapText(true);
        writer.write(rows);

        String fileName = "商品统计信息-" + DateUtil.date() + ".xls";
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    /**
     * 导出订单明细
     *
     * @param response 网络信息
     * @param token    token
     * @param pageVO   搜索条件
     */
    @Override
    public void exportOrderDetails(HttpServletResponse response, @Valid MemberSalesCountOrderDetailsVO pageVO, String token,String referer) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(token);
        Integer source = loginUser.getLoginSource();
        Long headerUserId = loginUser.getUserId();
        List<MemberSalesCountOrderDetailsQueryVO> orderDetailsQueryList = new ArrayList<>();
        pageVO.setCurrent(0);
        pageVO.setPageSize(0);
        Wrapper<PageData<MemberSalesCountOrderDetailsQueryVO>> orderDetailsQueryListVO = orderCount(source,referer,token,loginUser.getMemberId(), loginUser.getMemberRoleId(),headerUserId, pageVO);
        if (ObjectUtil.isNotNull(orderDetailsQueryListVO.getData())) {
            orderDetailsQueryList.addAll(orderDetailsQueryListVO.getData().getData());
        }
        // 商品数据不为空时
        List<Map<String, Object>> rows = orderDetailsQueryList.stream().map(order -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("销售订单号", order.getOrderNo());
            if (StringUtils.hasLength(order.getSpec())) {
                map.put("商品名称规格属性", order.getCommodityName().concat("-").concat(order.getSpec()));
            } else {
                map.put("商品名称规格属性", order.getCommodityName());
            }
            map.put("品类", order.getCategory());
            map.put("数量", order.getQuantity());
            map.put("单价", order.getPrice());
            map.put("优惠减免", ObjectUtils.isEmpty(order.getPreferentialRelief()) ? BigDecimal.ZERO : order.getPreferentialRelief());
            map.put("商品已付金额", ObjectUtils.isEmpty(order.getPaidAmount()) ? BigDecimal.ZERO : order.getPaidAmount());
            map.put("商品售后退款金额", ObjectUtils.isEmpty(order.getReturnAmount()) ? BigDecimal.ZERO : order.getReturnAmount());
            map.put("所属业务员", order.getName());
            map.put("下级会员名称", order.getBuyMemberName());
            map.put("订单完成时间", order.getFinishTime());
            return map;
        }).collect(Collectors.toList());

        ExcelWriter writer = ExcelUtil.getBigWriter();
        setWriterColumnWidth(writer);
        CellStyle headCellStyle = writer.getHeadCellStyle();
        headCellStyle.setWrapText(true);
        writer.write(rows);

        String fileName = "业绩订单明细-" + DateUtil.date() + ".xls";
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }

    }

    private void setWriterColumnWidth(ExcelWriter writer) {
        //销售订单号
        writer.setColumnWidth(0, 20);
        //商品名称属性规格
        writer.setColumnWidth(1, 70);
        // 品类
        writer.setColumnWidth(2, 40);
        // 数量
        writer.setColumnWidth(3, 20);
        // 单价
        writer.setColumnWidth(4, 20);
        // 优惠减免
        writer.setColumnWidth(5, 20);
        // 商品应付金额
        writer.setColumnWidth(6, 20);
        // 商品已付金额
        writer.setColumnWidth(7, 20);
        // 商品售后退款金额
        writer.setColumnWidth(8, 20);
        // 所属业务员
        writer.setColumnWidth(9, 30);
        // 下单会员名称
        writer.setColumnWidth(10, 30);
        // 订单完成时间
        writer.setColumnWidth(11, 40);
    }

    /**
     * 订单类型
     */
    private List<Integer> orderTypes() {
        List<Integer> orderTypes = new ArrayList<>();
        orderTypes.add(OrderTypeEnum.INQUIRY_TO_PURCHASE.getCode());
        orderTypes.add(OrderTypeEnum.SPOT_PURCHASING.getCode());
        orderTypes.add(OrderTypeEnum.CHANNEL_STRAIGHT_MINING.getCode());
        orderTypes.add(OrderTypeEnum.CHANNEL_SPOT.getCode());
        return orderTypes;
    }

    /**
     * 业务员业绩统计
     *
     * @param token   token
     * @param referer 当前页面的路径
     * @param pageVO  查询条件
     * @return 根据数据权限，查询统计业务员的业绩
     */
    private Wrapper<PageData<MemberSalesAchievementCountVO>> achievementCount(String token, String referer, OrderMemberSalesCountVO pageVO) {
        // 根据登录的用户信息和页面路径，去redis中查询数据权限
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(token);
        Integer source = loginUser.getLoginSource();
        Long headerUserId = loginUser.getUserId();
        String authUrl = "";
        try {
            assert referer != null;
            URI uri = new URI(referer);
            authUrl = uri.getPath();
        } catch (Exception ignored) {
        }
        // 从Redis缓存中读取用户数据权限配置，如果没有数据权限配置，则返回的是Null
        String dataAuthKey = String.format(DataAuthConstant.DATA_AUTH_CACHE_KEY_FORMAT, token, headerUserId, source);
        DataAuthDto dataAuthDto = (DataAuthDto) RedisServiceHolder.redisUtils.hGet(dataAuthKey, authUrl, Constants.REDIS_USER_INDEX);

        // 构建调用会员服务的VO
        MemberSalesCountFeignVO memberSalesCountFeignVO = new MemberSalesCountFeignVO(loginUser.getMemberId(), loginUser.getMemberRoleId(), pageVO.getTitle(), pageVO.getName(), pageVO.getCurrent(), pageVO.getPageSize());
        Wrapper<PageData<MemberFeignSalesCountVO>> wrapper = null;
        // 远程调用得到业务员信息
        if (dataAuthDto != null) {
            List<Long> userIds = dataAuthDto.getUserIds();
            memberSalesCountFeignVO.setUserIds(userIds);
            wrapper = memberAbilitySalesFeign.memberSalesList(memberSalesCountFeignVO);
        } else {
            wrapper = memberAbilitySalesFeign.memberSalesList(memberSalesCountFeignVO);
        }

        // 判断从远程调用得到业务员信息是否为空
        if (ObjectUtil.isNull(wrapper) || ObjectUtil.isNull(wrapper.getData()) || CollectionUtil.isEmpty(wrapper.getData().getData())) {
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        List<MemberFeignSalesCountVO> memberSalesList = wrapper.getData().getData();

        // 拼接时间，得到用户选择的月开始时间和月结束时间
        String currentTime = pageVO.getStartTime().concat("-01");
        LocalDate selectTime = LocalDate.parse(currentTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDateTime startTime = LocalDateTime.of(selectTime, LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime endTime = LocalDateTime.of(selectTime, LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());

        // userId 用户id
        List<Long> userId = memberSalesList.stream().map(MemberFeignSalesCountVO::getUserId).collect(Collectors.toList());
        // 消费者的角色Id
        Wrapper<List<Long>> roleIdsWrapper = memberAbilitySalesFeign.roleIds();
        List<Long> roleIds = roleIdsWrapper.getData();
        // 订单类型
        List<Integer> orderTypes = orderTypes();

        // 根据业务员Id，角色Id和每个会员的会员Id和角色Id查询所有订单
        QOrderDO qOrder = QOrderDO.orderDO;
        JPAQuery<OrderDO> query = jpaQueryFactory.select(Projections.constructor(OrderDO.class, qOrder.id, qOrder.buyerUserId, qOrder.vendorUserId, qOrder.totalAmount, qOrder.paidAmount))
                .from(qOrder)
                .where(qOrder.vendorUserId.in(userId))
                .where(qOrder.orderType.in(orderTypes))
                .where(qOrder.buyerRoleId.in(roleIds))
                .where(qOrder.outerStatus.eq(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))
                .where(qOrder.finishTime.after(startTime).and(qOrder.finishTime.before(endTime)));
        List<OrderDO> orderList = query.fetch();

        // 对查询到的订单数据和业务员信息进行相结合统计
        List<MemberSalesAchievementCountVO> result = memberSalesList.stream().map(sales -> {
            MemberSalesAchievementCountVO viewVO = new MemberSalesAchievementCountVO();
            // 符合条件的订单
            List<OrderDO> orders = orderList.stream().filter(order -> order.getVendorUserId().equals(sales.getUserId())).collect(Collectors.toList());
            // 业务员Id
            viewVO.setUserId(sales.getUserId());
            // 业务员名字
            viewVO.setName(sales.getName());
            // 业务员组织机构
            viewVO.setTitle(sales.getOrgName());
            // 下级的会员数
            ArrayList<MemberFeignUserListVO> count = sales.getMemberFeignUserListVO().stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(s -> s.getMemberId() + ";" + s.getRoleId()))), ArrayList::new));
            viewVO.setMemberCount(count.size());
            if (!CollectionUtils.isEmpty(orders)) {
                // 订单数据不为空的时候，进行订单统计
                // 总下单数
                ArrayList<OrderDO> orderCount = orders.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(OrderDO::getId))), ArrayList::new));
                viewVO.setOrderCount(orderCount.size());
                // 下单总金额
                BigDecimal totalAmount = orders.stream().map(OrderDO::getTotalAmount).reduce(new BigDecimal(0), BigDecimal::add);
                viewVO.setAmountPayable(totalAmount);
                // 已付金额
                BigDecimal paidAmount = orders.stream().map(OrderDO::getPaidAmount).reduce(new BigDecimal(0), BigDecimal::add);
                viewVO.setAmountPaid(paidAmount);
                // 退款金额
                List<Long> orderIds = orders.stream().map(OrderDO::getId).collect(Collectors.toList());
                BigDecimal refundAmount = orderRepository.findByOrderRefundAmount(orderIds);
                if (ObjectUtils.isEmpty(refundAmount)) {
                    viewVO.setRefundAmount(new BigDecimal(0));
                } else {
                    viewVO.setRefundAmount(refundAmount);
                }
            } else {
                // 订单数据为空的时候，业务员相关的订单统计设置为0
                viewVO.setOrderCount(0);
                viewVO.setAmountPayable(new BigDecimal(0));
                viewVO.setAmountPaid(new BigDecimal(0));
                viewVO.setRefundAmount(new BigDecimal(0));
            }
            return viewVO;
        }).collect(Collectors.toList());

        // 4.根据会员Id和角色Id，查找对应的订单数据并进行统计
        return Wrapper.success(new PageData<>(wrapper.getData().getTotalCount(), result));
    }

    /**
     * 会员详情业务统计
     */
    private Wrapper<PageData<MemberSalesMemberQueryVO>> memberCount(Long memberId, Long memberRoleId, @Valid MemberSalesMemberCountVO pageVO) {
        // 根据前端传的时间，得到这个月的开始时间和结束时间
        String currentTime = pageVO.getCountTime().concat("-01");
        LocalDate selectTime = LocalDate.parse(currentTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDateTime startTime = LocalDateTime.of(selectTime, LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime endTime = LocalDateTime.of(selectTime, LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());

        // 构造查询会员服务的参数
        MemberSalesFindUserIdVO userIdVO = new MemberSalesFindUserIdVO(memberId, memberRoleId, pageVO.getUserId(), pageVO.getMemberName(), endTime, pageVO.getCurrent(), pageVO.getPageSize());
        Wrapper<PageData<MemberSalesFeignPageQueryVO>> userWrapper = memberAbilitySalesFeign.findByUserId(userIdVO);
        if (ObjectUtil.isNull(userWrapper.getData()) || CollectionUtil.isEmpty(userWrapper.getData().getData())) {
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        // 得到该业务员下的所有下级会员
        List<MemberSalesFeignPageQueryVO> memberList = userWrapper.getData().getData();
        List<MemberSalesMemberQueryVO> memberCountList;

        // 订单类型
        List<Integer> orderTypes = orderTypes();

        // 根据下级会员Id和会员角色Id找到该业务员下的绑定会员订单
        Specification<OrderDO> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicateList = new ArrayList<>();

            // 根据条件参数查询订单信息，orList 为 (memberId1 and roleId1) or (memberId2 and roleId2) or (memberId3 and roleId3)
            List<Predicate> orList = new ArrayList<>();
            for (MemberSalesFeignPageQueryVO memberCount : memberList) {
                orList.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("buyerMemberId").as(Long.class), memberCount.getMemberId()),
                        criteriaBuilder.equal(root.get("buyerRoleId").as(Long.class), memberCount.getMemberRoleId()),
                        criteriaBuilder.equal(root.get("vendorUserId").as(Long.class), pageVO.getUserId()),
                        criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), OrderOuterStatusEnum.ACCOMPLISHED.getCode()),
                        criteriaBuilder.in(root.get("orderType")).value(orderTypes),
                        //用户查找的月份 大于等于开始时间  小于等于结束时间
                        criteriaBuilder.greaterThanOrEqualTo(root.get("finishTime").as(LocalDateTime.class), startTime),
                        criteriaBuilder.lessThanOrEqualTo(root.get("finishTime").as(LocalDateTime.class), endTime)));
            }
            Predicate[] orListPredicate = new Predicate[orList.size()];
            predicateList.add(criteriaBuilder.or(orList.toArray(orListPredicate)));

            Predicate[] predicate = new Predicate[predicateList.size()];
            return criteriaBuilder.and(predicateList.toArray(predicate));
        };
        // 得到订单信息
        List<OrderDO> orderList = orderRepository.findAll(spec);

        // 将订单信息转成前端展示的MemberSalesMemberQueryVO，并对订单信息进行统计
        memberCountList = memberList.stream().map(member -> {
            MemberSalesMemberQueryVO viewVO = new MemberSalesMemberQueryVO();
            // 符合条件的订单
            List<OrderDO> orders = orderList.stream().filter(o -> member.getMemberId().equals(o.getBuyerMemberId()) && member.getMemberRoleId().equals(o.getBuyerRoleId())).collect(Collectors.toList());
            // 会员Id
            viewVO.setMemberId(member.getMemberId());
            // 会员名字
            viewVO.setMemberName(member.getMemberName());
            // 会员角色Id
            viewVO.setMemberRoleId(member.getMemberRoleId());
            // 会员角色名称
            viewVO.setRoleName(member.getRoleName());

            if (!CollectionUtils.isEmpty(orders)) {
                // 订单数据不为空的时候，进行订单统计
                // 总下单数
                viewVO.setOrderCount(orders.size());
                // 下单总金额
                BigDecimal totalAmount = orders.stream().map(OrderDO::getTotalAmount).reduce(new BigDecimal(0), BigDecimal::add);
                viewVO.setAmountPayable(totalAmount);
                // 已付金额
                BigDecimal paidAmount = orders.stream().map(OrderDO::getPaidAmount).reduce(new BigDecimal(0), BigDecimal::add);
                viewVO.setAmountPaid(paidAmount);
                // 退款金额
                List<Long> orderIds = orders.stream().map(OrderDO::getId).collect(Collectors.toList());
                BigDecimal refundAmount = orderRepository.findByOrderRefundAmount(orderIds);
                if (ObjectUtils.isEmpty(refundAmount)) {
                    viewVO.setRefundAmount(new BigDecimal(0));
                } else {
                    viewVO.setRefundAmount(refundAmount);
                }

            } else {
                // 订单数据为空的时候，业务员相关的订单统计设置为0
                viewVO.setOrderCount(0);
                viewVO.setAmountPayable(new BigDecimal(0));
                viewVO.setAmountPaid(new BigDecimal(0));
                viewVO.setRefundAmount(new BigDecimal(0));
            }
            return viewVO;
        }).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(user -> user.getMemberId() + ";" + user.getMemberRoleId()))), ArrayList::new));

        return Wrapper.success(new PageData<>(userWrapper.getData().getTotalCount(), memberCountList));
    }

    /**
     * 商品统计详情
     */
    public PageData<MemberSalesCountCommodityQueryVO> commodityInformation(@Valid MemberSalesCountCommodityVO pageVO) {
        // 拼接时间，得到用户选择的时间
        String currentTime = pageVO.getCountTime().concat("-01");
        LocalDate selectTime = LocalDate.parse(currentTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 月开始时间
        LocalDateTime startTime = LocalDateTime.of(selectTime, LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        // 月结束时间
        LocalDateTime endTime = LocalDateTime.of(selectTime, LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());

        List<Integer> orderTypes = orderTypes();
        // 消费者的角色Id
        Wrapper<List<Long>> roleIdsWrapper = memberAbilitySalesFeign.roleIds();
        List<Long> roleIds = roleIdsWrapper.getData();
        // 根据业务员Id去订单表找查找相应的数据
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;
        JPAQuery<MemberSalesCountCommodityQueryVO> query = jpaQueryFactory.select(Projections.constructor(MemberSalesCountCommodityQueryVO.class, qOrderProduct.skuId, qOrderProduct.name, qOrderProduct.category, qOrderProduct.spec, qOrderProduct.quantity.sum(), (qOrderProduct.refPrice.multiply(qOrderProduct.quantity)).sum(), qOrderProduct.paidAmount.sum(), qOrderProduct.refReturnAmount.sum()))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .where(qOrder.vendorUserId.eq(pageVO.getUserId()))
                .where(qOrder.orderType.in(orderTypes))
                .where(qOrder.buyerRoleId.in(roleIds))
                .where(qOrder.outerStatus.eq(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))
                .where(qOrder.finishTime.after(startTime).and(qOrder.finishTime.before(endTime)))
                .groupBy(qOrderProduct.skuId, qOrderProduct.name, qOrderProduct.category, qOrderProduct.spec);

        if (StringUtils.hasLength(pageVO.getCategory())) {
            query.where(qOrderProduct.category.like("%" + pageVO.getCategory().trim() + "%"));
        }

        if (StringUtils.hasLength(pageVO.getCommodityName())) {
            query.where(qOrderProduct.name.like("%" + pageVO.getCommodityName().trim() + "%"));
        }
        if (pageVO.getCurrent() != 0 && pageVO.getPageSize() != 0) {
            query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset());
        }
        //总数
        long totalCount = query.fetch().size();
        List<MemberSalesCountCommodityQueryVO> result = query.orderBy(qOrderProduct.skuId.asc()).fetch();
        return new PageData<>(totalCount, result);

    }

    /**
     * 订单详情
     */
    public Wrapper<PageData<MemberSalesCountOrderDetailsQueryVO>> orderCount(Integer source,String referer,String token,Long memberId, Long memberRoleId,Long headerUserId, @Valid MemberSalesCountOrderDetailsVO pageVO) {
        MemberSalesCountFeignVO vo = new MemberSalesCountFeignVO();
        String authUrl = "";
        try {
            assert referer != null;
            URI uri = new URI(referer);
            authUrl = uri.getPath();
        } catch (Exception ignored) {
        }
        // 从Redis缓存中读取用户数据权限配置，如果没有数据权限配置，则返回的是Null
        String dataAuthKey = String.format(DataAuthConstant.DATA_AUTH_CACHE_KEY_FORMAT, token, headerUserId, source);
        DataAuthDto dataAuthDto = (DataAuthDto) RedisServiceHolder.redisUtils.hGet(dataAuthKey, authUrl, Constants.REDIS_USER_INDEX);
        if (dataAuthDto != null) {
            List<Long> userIds = dataAuthDto.getUserIds();
            if(userIds.contains(pageVO.getUserId())){
                vo.setUserIds(userIds);
            }else {
                return Wrapper.success(new PageData<>(0L, null));
            }

        }
        // 拼接时间，得到用户选择的时间
        String currentTime = pageVO.getCountTime().concat("-01");
        LocalDate selectTime = LocalDate.parse(currentTime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        // 月开始时间
        LocalDateTime startTime = LocalDateTime.of(selectTime, LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        // 月结束时间
        LocalDateTime endTime = LocalDateTime.of(selectTime, LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());

        // 远程调用得到业务员信息

        vo.setMemberId(memberId);
        vo.setMemberRoleId(memberRoleId);
        vo.setCurrent(1);
        vo.setPageSize(1000);
        Wrapper<List<MemberUserVO>> userIdsWrapper = memberAbilitySalesFeign.getUserIds(vo);

        // 订单类型
        List<Integer> orderTypes = orderTypes();

        // 角色Id
        Wrapper<List<Long>> listWrapper = memberAbilitySalesFeign.roleIds();
        List<Long> roleIds = listWrapper.getData();

        // 业务员Id
        List<Long> userIds;
        List<MemberUserVO> users = userIdsWrapper.getData();
        if (ObjectUtil.isNull(pageVO.getUserId())) {
            // 默认不选择业务员时，得到符合条件的userId
            userIds = users.stream().map(MemberUserVO::getUserId).collect(Collectors.toList());
        } else {
            userIds = new ArrayList<>();
            userIds.add(pageVO.getUserId());
        }
        int endNum = pageVO.getCurrent() * pageVO.getPageSize();

        List<MemberSalesCountOrderDetailsQueryListVO> result = orderCountQuery(orderTypes, roleIds, userIds, startTime, endTime, pageVO);
        pageVO.setCurrent(0);
        pageVO.setPageSize(0);
        List<MemberSalesCountOrderDetailsQueryListVO> resultCount = orderCountQuery(orderTypes, roleIds, userIds, startTime, endTime, pageVO);
        //根据订单的userId 和对应的会员信息的userId 为订单信息添加业务员名称
        List<MemberSalesCountOrderDetailsQueryVO> resultVO = result.stream().map(listVO -> {
            List<String> userNameList = users.stream().filter(member -> member.getUserId().equals(listVO.getUserId())).map(MemberUserVO::getUserName).collect(Collectors.toList());
            MemberSalesCountOrderDetailsQueryVO queryVO = new MemberSalesCountOrderDetailsQueryVO();
            BeanUtils.copyProperties(listVO, queryVO);
            queryVO.setName(userNameList.get(0));
            return queryVO;
        }).collect(Collectors.toList());
        List<MemberSalesCountOrderDetailsQueryVO> results = resultVO.stream().sorted(Comparator.comparing(MemberSalesCountOrderDetailsQueryVO::getFinishTime).reversed()).collect(Collectors.toList());

        for (int i=0;i<results.size();i++){
            results.get(i).setOrderById(endNum+i);
       }
        return Wrapper.success(new PageData<>((long) resultCount.size(), results));
    }

    /**
     * 订单详情查询
     */
    private List<MemberSalesCountOrderDetailsQueryListVO> orderCountQuery(List<Integer> orderTypes, List<Long> roleIds, List<Long> userIds, LocalDateTime startTime, LocalDateTime endTime, MemberSalesCountOrderDetailsVO pageVO) {
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;

        JPAQuery<MemberSalesCountOrderDetailsQueryListVO> query =
                jpaQueryFactory.select(Projections.constructor(MemberSalesCountOrderDetailsQueryListVO.class, qOrderProduct.skuId, qOrder.orderNo, qOrder.id, qOrderProduct.name, qOrderProduct.spec, qOrderProduct.category, qOrderProduct.quantity, qOrderProduct.price, (qOrderProduct.price.subtract(qOrderProduct.refPrice)), (qOrderProduct.refPrice.multiply(qOrderProduct.quantity)), qOrderProduct.paidAmount, qOrderProduct.refReturnAmount, qOrder.vendorUserId, qOrder.buyerMemberName, qOrder.finishTime))
                        .from(qOrderProduct)
                        .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                        .where(qOrder.orderType.in(orderTypes))
                        .where(qOrder.buyerRoleId.in(roleIds))
                        .where(qOrder.vendorUserId.in(userIds))
                        .where(qOrder.outerStatus.eq(OrderOuterStatusEnum.ACCOMPLISHED.getCode()))
                        .where(qOrder.finishTime.after(startTime).and(qOrder.finishTime.before(endTime)))
                        .groupBy(qOrderProduct.skuId, qOrder.orderNo, qOrder.id, qOrderProduct.name, qOrderProduct.spec, qOrderProduct.category, qOrderProduct.quantity, qOrderProduct.price, qOrderProduct.refPrice, qOrderProduct.paidAmount, qOrderProduct.refReturnAmount, qOrder.vendorUserId, qOrder.buyerMemberName)
                        .orderBy(qOrderProduct.skuId.asc());

        if (StringUtils.hasLength(pageVO.getSubMemberName())) {
            query.where(qOrder.buyerMemberName.eq(pageVO.getSubMemberName()));
        }
        if (ObjectUtil.isNotNull(pageVO.getSubMemberId())) {
            query.where(qOrder.buyerMemberId.eq(pageVO.getSubMemberId()));
        }
        if (ObjectUtil.isNotNull(pageVO.getSubMemberRoleId())) {
            query.where(qOrder.buyerRoleId.eq(pageVO.getSubMemberRoleId()));
        }
        if (ObjectUtil.isNotNull(pageVO.getSkuId())) {
            query.where(qOrderProduct.skuId.eq(pageVO.getSkuId()));
        }
        if (StringUtils.hasLength(pageVO.getCategory())) {
            query.where(qOrderProduct.category.like("%" + pageVO.getCategory().trim() + "%"));
        }

        if (StringUtils.hasLength(pageVO.getCommodityName())) {
            query.where(qOrderProduct.name.like("%" + pageVO.getCommodityName().trim() + "%"));
        }

        if (pageVO.getPageSize() != 0 && pageVO.getCurrent() != 0) {
            query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset());
        }

        return query.fetch();
    }


}
